import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;

/**
 * 接入建融慧学demo
 */
public class Demo {
    //SM4密钥
    private static String sm4Key="Tedq9HdJIYmDnjPOmRAs1Q==";
    //SM3私钥
    private static String sm3PriKey = "30820154020100300D06092A864886F70D01010105000482013E3082013A02010002410090FE4F2A550FFE149285C97966B001C9A8BE2DFA2AE0B882896411FC137287B232B203F550BA3BF1A0F5F1A74BBC3A72CF24534177A7103E2967F22813E1ED410203010001024007B697A650B1CAD32D02B78D0BB84244883C5C6E583FB4EF4D401E3024B47B8BC69850B1B5C504C10232BF8987A77F8815C064D1458FDE058A955BE8C2A926B7022100C97FCB3E01D6F0B414DCBA8FA731042E0C320A9D640F6E7C9A3F81D1EA001887022100B835F0EAE2D87C682AF5550C0B16ADFFF03450B7D77A14358A3255FBBB3B65F702201B1A3C4D1FD4385610844BF7AC865448994D55CE2BBA43A330E01FE70B316E1B02201276CDAC2D8AB7859570BBD29635F2C0E9A9C4C178A6B2E9DEED46B311C45567022100C3E7B43D029F24505C6BA557F2FF7E1EC83D3FD34263DC13DB45659A244012B3";

    private static final String TRANSFORMATION = "SM4/ECB/PKCS5Padding";  //ECB模式
    private static final String ALGORITHM = "SM4"; //加密算法
    private static String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());

    //添加Bouncy Castle作为算法提供者
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) throws Exception{
        System.out.println("接入建融慧学测试");
        String head_url = "https://app.xiaoyuan.ccb.com/LHECISM/CCBLNTServiceReqServlet?ChanlNo=";
        String ChanlNo = "wx9c7b93ae557aefb8";
        //请求数据加密（如：调用获取学校信息列表接口）
        String ccbParam = encrypt(YXDL08(), sm4Key);
        //生成签名串
        String sign = generateSign("ChanlNo="+ChanlNo+"&ccbParam="+ccbParam, sm3PriKey);
        //拼接完整请求串，注意ccbParam需要URLEncode
        String url = head_url+ChanlNo+"&sign="+sign+"&ccbParam="+ URLEncoder.encode(ccbParam,"UTF-8");
        System.out.println(url);
    }


    /**
     * 将数据加密
     */
    public static String encrypt(String plaintext, String key) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION, "BC");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.getDecoder().decode(key), ALGORITHM));
        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * 生成签名串
     */
    public static String generateSign(String signText, String priKey) {
        //计算摘要
        byte[] digest = new byte[0];
        try {
            digest = calculateDigest(signText.getBytes());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        //对数据进行签名
        byte[] signature = new byte[0];
        try {
            signature = sign(digest, priKey);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return bytesToHex(signature);
    }

    /**
     *使用私钥对数据进行签名
     */
    public static byte[] sign(byte[] data, String privateKeyStr) throws Exception {
        //使用SHA256withRSA算法进行签名
        Signature signature = Signature.getInstance("SHA256withRSA", "BC");
        byte[] privateKeyBytes = Hex.decode(privateKeyStr);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
        PrivateKey privateKey = keyFactory.generatePrivate(spec);
        signature.initSign(privateKey); signature.update(data);
        return signature.sign();
    }

    /**
     *将字节数组转换为16进制字符串
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02X", b));
        }
        return result.toString();
    }

    /**
     * 计算摘要
     */
    public static byte[] calculateDigest(byte[] data) throws Exception {
        MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC");
        return messageDigest.digest(data);
    }

    /**
     * 获取学校信息列表接口
     */
    public static String YXY122(){
        String ccbParm = "TXCODE=YXY122&BRANCHID=410000000&PAGE_SIZE=10&CURRENT_PAGE=1&USER_TYPEIN=体验"
                +"&USER_LONGITUDE=112.30&USER_LATITUDE=29.14";
        return ccbParm;
    }

    /**
     * 跳转收银台（校友）
     */
    public static String YXDL08(){
        String st_id="qht2510";
        String order_id="TSETYXDL08"+date;
        String ccbParm = "TXCODE=YXDL08&APPID=wx9c7b93ae557aefb8&APPNAME=川大校友会&OPENID=&SCHOOLID=1061002"
                +"&STUDENTID="+st_id+"&NAME=邱浩涛&CARD_TPCD=06&TM="+date+"&RETURN_URL=&ORDER_ID="+order_id+"&AMOUNT=0.01&SCENE_CODE=12";
        return ccbParm;
    }
}
